module ActiveDirectorySearch
  
  # generate controller method to handle autocompleter
  def active_directory_auto_complete_for(object, method, options = {})
    define_method("auto_complete_for_#{object}_#{method}") do
		  searcher = ActiveDirectorySearcher.new
  		searcher.initialization
  		@items = searcher.search object, method, params[object][method], 10		
      render :inline => "<%= active_directory_auto_complete_result @items, '#{method}' %>"    
    end
  end
  
  # server autocompleter results (this is a helper method)
  def active_directory_auto_complete_result(entries, field, phrase = nil)
    return unless entries
    items = Array.new
    entries.each do |entry| 
      items << content_tag(:li, entry)
    end
    content_tag(:ul, items)
  end

  class ActiveDirectorySearcher
    connection = nil
    host = nil
    port = nil
    domain = nil
    dn = nil

    def initialization()
      # load configuration
      config = YAML::load(File.open("#{RAILS_ROOT}/config/active_directory.yml"))
      @host = config["host"]
      @port = config["port"]
      @domain = config["domain"]
      @dn = config["dn"]
      @ldap_search_conditions = config["ldap_search_conditions"]
      @user = config["user"]
      @password = config["password"]			
    end

    def search(object, method, query, limit = -1)

      begin
        email = @user + "@" + @domain
        connection = LDAP::Conn.new(@host, @port)
        connection.set_option(LDAP::LDAP_OPT_PROTOCOL_VERSION, 3)
        connection.bind(email, @password)

        ldap_query = "(&(#{method}=*#{query}*)#{@ldap_search_conditions})"

        @people = Array.new
        resultCount = 0
        
        connection.search(@dn, LDAP::LDAP_SCOPE_SUBTREE, ldap_query) do |ad_user|
          if (limit == -1)
            @people << ad_user.vals("displayName").to_s
          elsif (limit != -1 and resultCount < limit)
            @people << ad_user.vals("displayName").to_s
            resultCount = resultCount + 1
          end
        end

        @connection = connection
        @people

      rescue => e
        puts e    # print out errors for now....
        nil
      end
    end

    def close
      @connection.unbind unless @connection == nil
      @connection = nil
    end
  end
  
end